package com.binance.basedao.mybatis;

import com.binance.basedao.anotation.Id;
import com.binance.basedao.complexquery.CustomQueryParam;
import org.apache.ibatis.session.RowBounds;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * <b>Description:</b>〈用于业务service继承的常用查询服务实现类〉<br/>
 * @author hongchaoMao <br/>
 *         Create date: 2017/9/18
 * @version v1.0.0
 */
public abstract class BaseServiceImpl<T> implements BaseService<T>
{
    private final Logger logger = Logger.getLogger(getClass().getName());

    @Autowired(required = false)
    private BaseMapper<T> baseMapper;
    
    @Override
    public List<T> getAll()
    {
        List<T> list = baseMapper.getAll();
        return list == null ? Collections.emptyList() : list;
    }
    
    @Override
    public T getById(Long id)
    {
        return baseMapper.getById(id);
    }

    @Override
    public T getOne(T findParams) {
        return baseMapper.getOne(findParams);
    }

    @Override
    public int count(T params)
    {
        return baseMapper.count(params);
    }
    
    @Override
    public int countLike(T findParams)
    {
        return baseMapper.countLike(findParams);
    }
    
    @Override
    public int countQuery(List<CustomQueryParam> customQueryParams)
    {
        return baseMapper.countQuery(customQueryParams);
    }
    
    @Override
    public List<T> query(List<CustomQueryParam> customQueryParams)
    {
        List<T> list = baseMapper.query(customQueryParams, null);
        return list == null ? Collections.emptyList() : list;
    }
    
    @Override
    public List<T> query(List<CustomQueryParam> customQueryParams, Integer start, Integer limit, List<Sort> sortList)
    {
        if (start != null && limit != null) {
            SqlInterceptor.setRowBounds(new RowBounds(start, limit));
        }
        List<T> list = baseMapper.query(customQueryParams, sortList);
        return list == null ? Collections.emptyList() : list;
    }
    
    @Override
    public List<T> findByObj(T findParams, Integer start, Integer limit)
    {
        if (start != null && limit != null) {
            SqlInterceptor.setRowBounds(new RowBounds(start, limit));
        }
        List<T> list = baseMapper.find(findParams);
        return list == null ? Collections.emptyList() : list;
    }

    @Override
    public List<T> findByObj(T findParams)
    {
        List<T> list = baseMapper.find(findParams);
        return list == null ? Collections.emptyList() : list;
    }
    
    @Override
    public List<T> getByObj(T findParams)
    {
        List<T> list = baseMapper.get(findParams);
        return list == null ? Collections.emptyList() : list;
    }

    @Override
    public List<T> getByObj(T findParams, Integer start, Integer limit)
    {
        if (start != null && limit != null) {
            SqlInterceptor.setRowBounds(new RowBounds(start, limit));
        }
        List<T> list = baseMapper.get(findParams);
        return list == null ? Collections.emptyList() : list;
    }

    @Override
    public List<T> getByObj(T findParams, Integer start, Integer limit, List<Sort> sortList)
    {
        if (start != null && limit != null) {
            SqlInterceptor.setRowBounds(new RowBounds(start, limit));
        }
        List<T> list = baseMapper.enhanceGet(findParams, sortList);
        return list == null ? Collections.emptyList() : list;
    }

    @Override
    @Transactional
    public void insert(T t) throws DataCommitException
    {
        if (baseMapper.insert(t, false) != 1) {
            throw new DataCommitException();
        }
    }

    @Override
    @Transactional
    public void insertIgnore(T t) throws DataCommitException
    {
        baseMapper.insert(t, true);
    }
    
    @Override
    @Transactional
    public void insert(List<T> list) throws DataCommitException
    {
        if (list != null && !list.isEmpty()) {
            for (T t : list) {
                insert(t);
            }
        }
    }
    
    @Override
    @Transactional
    public void batchInsert(List<T> list) throws DataCommitException
    {
        if (list != null && !list.isEmpty()) {
            if(baseMapper.insertBatch(list, false) < 1) {
                throw new DataCommitException();
            }
        }
    }

    @Override
    @Transactional
    public void batchInsertIgnore(List<T> list) throws DataCommitException
    {
        if (list != null && !list.isEmpty()) {
            baseMapper.insertBatch(list, true);
        }
    }

    
    @Override
    @Transactional
    public void deleteById(Long id) throws DataCommitException
    {
        if (baseMapper.deleteById(id) != 1) {
            throw new DataCommitException("The id value[" + id +"] may be not exist !");
        }
    }
    
    @Override
    @Transactional
    public void deleteByIds(List<Long> ids) throws DataCommitException
    {
        for (Long id : ids) {
            deleteById(id);
        }
    }
    
    @Override
    @Transactional
    public void delete(T t) throws DataCommitException
    {
        if (baseMapper.deleteByPrimaryKey(t) != 1) {
            throw new DataCommitException("The @Id field value[" + getPrimaryKey(t) +"] may be not exist in DB!");
        }
    }

    private Object getPrimaryKey(T t) {
        Class<?> clazz = t.getClass();
        Field[] fields = clazz.getDeclaredFields();
        for (Field field: fields) {
            Id idAnnotaion = field.getAnnotation(Id.class);
            if (idAnnotaion != null) {
                String name = field.getName();
                String readMethod = "get" + name.substring(0, 1).toUpperCase() + name.substring(1);
                try {
                    Method read = clazz.getMethod(readMethod);
                    if (read != null) {
                        read.setAccessible(true);
                        return read.invoke(t);
                    }
                } catch (Exception ex) {
                    logger.log(Level.WARNING, "Error occurred when get the primary id value -> " + ex);
                }
                break;
            }
        }
        return null;
    }
    
    @Override
    @Transactional
    public void delete(List<T> list) throws DataCommitException
    {
        for (T t : list) {
            delete(t);
        }
    }
    
    @Override
    @Transactional
    public void update(T t) throws DataCommitException
    {
        if (baseMapper.update(t) != 1) {
            throw new DataCommitException("The @Id field value[" + getPrimaryKey(t) +"] may be not exist in DB!");
        }
    }
    
    @Override
    @Transactional
    public void update(List<T> list) throws DataCommitException
    {
        if (list != null && !list.isEmpty()) {
            for (T t : list) {
                update(t);
            }
        }
    }

}

